#include "XenStats.h"

char XenStats::displayStats = 1;

void myCreateTexture(LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, LPDIRECT3DTEXTURE9 *ppTexture) {
	HRESULT result;

	result = D3DXCreateTextureFromFile(pDevice, pSrcFile, ppTexture);
	if (result) {
		Utils::Log(LOGFILE, "Couldn't find ");
		Utils::Log(LOGFILE, pSrcFile);
		Utils::Log(LOGFILE, "\n");
	}
}

XenStats::XenStats(IDirect3DDevice9 *pIDirect3DDevice9)
{
	this->pIDirect3DDevice9 = pIDirect3DDevice9;
	Initialize();
}

void XenStats::Initialize()
{
	xenMemory = new XenMemory();

	D3DVIEWPORT9 viewport;
	pIDirect3DDevice9->GetViewport(&viewport);

	screenWidth = viewport.Width;
	screenHeight = viewport.Height;

	scaleX = screenWidth / (float)DEFAULTSCREENWIDTH;
	scaleY = screenHeight / (float)DEFAULTSCREENHEIGHT;

	//Set maxHp/maxMp initial values (-1 means not to display them)
	maxHp = -1;
	maxMp = -1;

	//Arc
	//D3DXCreateTextureFromFile(pIDirect3DDevice9, STATSARC_LOC, &arcoOrigTexture);

	//D3DXCreateTextureFromFileEx(pIDirect3DDevice9, STATSARC_LOC, 0, 0, 1 ,0 ,D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_FILTER_NONE ,D3DX_FILTER_NONE ,0 ,NULL ,NULL ,&arcTexture);
	myCreateTexture(pIDirect3DDevice9, STATSARC_LOC, &hpTopArcTexture);
	myCreateTexture(pIDirect3DDevice9, STATSARC_LOC, &hpBottomArcTexture);
	myCreateTexture(pIDirect3DDevice9, STATSARC_LOC, &mpTopArcTexture);
	myCreateTexture(pIDirect3DDevice9, STATSARC_LOC, &mpBottomArcTexture);
	myCreateTexture(pIDirect3DDevice9, STATSARC_LOC, &xpTopArcTexture);
	myCreateTexture(pIDirect3DDevice9, STATSARC_LOC, &xpBottomArcTexture);
	D3DXCreateSprite(pIDirect3DDevice9, &arcSprite);

	//Stats Background
	myCreateTexture(pIDirect3DDevice9, STATSBG_LOC, &statsBgTexture);
	D3DXCreateSprite(pIDirect3DDevice9, &statsBgSprite);

	//Stats HP Display
	myCreateTexture(pIDirect3DDevice9, STATSHP_LOC, &statsHpTexture);
	D3DXCreateSprite(pIDirect3DDevice9, &statsHpSprite);

	//Stats MP Display
	myCreateTexture(pIDirect3DDevice9, STATSMP_LOC, &statsMpTexture);
	D3DXCreateSprite(pIDirect3DDevice9, &statsMpSprite);

	//Stats MP Display
	myCreateTexture(pIDirect3DDevice9, STATSXP_LOC, &statsXpTexture);
	D3DXCreateSprite(pIDirect3DDevice9, &statsXpSprite);

	ZeroMemory(&fStats, sizeof(D3DXFONT_DESC));
	strcpy(fStats.FaceName, "Arial");
	fStats.Height = -16 * (int)scaleY;
	D3DXCreateFontIndirect(pIDirect3DDevice9, &fStats,&statsHpFont);
	D3DXCreateFontIndirect(pIDirect3DDevice9, &fStats,&statsMpFont);
	D3DXCreateFontIndirect(pIDirect3DDevice9, &fStats,&statsXpFont);
}
void XenStats::Render()
{
	if (xenMemory->ReadPage() == 1) { //Main menu
		//Set maxHp/maxMp initial values (-1 means not to display them)
		maxHp = -1;
		maxMp = -1;
	}

	if (xenMemory->ReadPage() == 0 && displayStats > 0) {
		if(displayStats == 1)
			RenderNewStats();
		else if (displayStats == 2)
			RenderOldStats();
	}
}
void XenStats::RenderNewStats()
{
	int offsetY = xenMemory->ReadViewVar() == 2 ? 110 * (int)scaleY : 0;
	D3DXVECTOR2 statBarsPos;
	statBarsPos.x = (float)screenWidth / 2 ;
	statBarsPos.y = (float)screenHeight / 2 - offsetY;

	D3DXVECTOR2 xpBarPos;
	xpBarPos.x = (float)screenWidth / 2;
	xpBarPos.y = (float)screenHeight / 2 + 70 - offsetY;

	bool rerender = false;

	//Render Mana
	static float mpPercent;
	if(xenMemory->ReadMPPercent() != mpPercent) {
		mpPercent = xenMemory->ReadMPPercent();
		rerender = true;
	}
	RenderBar(mpPercent, false, 0, 0, 255, statBarsPos, mpTopArcTexture, mpBottomArcTexture, rerender, 1.0);

	//Render HP
	static float hpPercent;
	if(xenMemory->ReadHPPercent() != hpPercent) {
		hpPercent = xenMemory->ReadHPPercent();
		rerender = true;
	}
	RenderBar(hpPercent, true, 255, 0, 0, statBarsPos, hpTopArcTexture, hpBottomArcTexture, rerender, 1.0);

	//Render XP
	static float xpPercent;
	if(xenMemory->ReadXPPercent() != xpPercent) {
		xpPercent = xenMemory->ReadXPPercent();
		rerender = true;
	}
	RenderBar(xpPercent, false, 255, 150, 0, xpBarPos, xpTopArcTexture, xpBottomArcTexture, rerender, 1.0, 90.0);

	RECT hpTextRect = { statBarsPos.x - 64, statBarsPos.y + 128, 0, 0 };
	string hpPctStr = Utils::ToString<int>(hpPercent * 100) + "%";
	statsHpFont->DrawText(NULL, hpPctStr.c_str(), -1, &hpTextRect, DT_CALCRECT, 0);
	statsHpFont->DrawText(NULL, hpPctStr.c_str(), -1, &hpTextRect, DT_RIGHT, D3DCOLOR_XRGB(255, 255, 255));

	RECT mpTextRect = { statBarsPos.x + 64, statBarsPos.y + 128, 0, 0 };
	string mpPctStr = Utils::ToString<int>(mpPercent * 100) + "%";
	statsHpFont->DrawText(NULL, mpPctStr.c_str(), -1, &mpTextRect, DT_CALCRECT, 0);
	mpTextRect.left -= mpTextRect.right - mpTextRect.left;
	statsHpFont->DrawText(NULL, mpPctStr.c_str(), -1, &mpTextRect, DT_LEFT, D3DCOLOR_XRGB(255, 255, 255));

	RECT xpTextRect = { statBarsPos.x, statBarsPos.y + 136, 0, 0 };
	string xpPctStr = " " + Utils::ToString<int>(xpPercent * 100) + "%";
	statsHpFont->DrawText(NULL, xpPctStr.c_str(), -1, &xpTextRect, DT_CALCRECT, 0);
	xpTextRect.left -= (xpTextRect.right - xpTextRect.left) / 2;
	statsHpFont->DrawText(NULL, xpPctStr.c_str(), -1, &xpTextRect, DT_LEFT, D3DCOLOR_XRGB(255, 255, 255));
}

void XenStats::RenderBar(float percent, bool left, byte r, byte g, byte b, D3DXVECTOR2 arcPos, LPDIRECT3DTEXTURE9 topArcTexture, LPDIRECT3DTEXTURE9 bottomArcTexture, bool redraw, float scale, float rotationAngle)
{
	float topAngle = percent > 0.5 ? (percent - 0.5) * 2.0 * 90.0 : 0.0;
	float bottomAngle = percent >= 0.5 ? 90.0 : percent * 2.0 * 90.0;

	//Render top half of bar
	RenderArc(topAngle, true, left, r, g, b, arcPos, topArcTexture, redraw, scale, rotationAngle);
	//Render bottom half of bar
	RenderArc(bottomAngle, false, left, r, g, b, arcPos, bottomArcTexture, redraw, scale, rotationAngle);

}

void XenStats::RenderArc(float angle, bool top, bool left, byte r, byte g, byte b, D3DXVECTOR2 arcPos, LPDIRECT3DTEXTURE9 arcTexture, bool redraw, float scale, float rotationAngle)
{
	if(!top)
		angle = 90 - angle;

	float angleRatio = tan(angle * PI / 180);

	D3DSURFACE_DESC arcDesc;
	arcTexture->GetLevelDesc(0, &arcDesc);

	D3DXVECTOR2 arcScale;
	//arcScale.x = left ? -1 * scaleX * scale: scaleX * scale;
	//arcScale.y = top ? -1 * scaleY * scale : scaleY * scale;

	arcScale.x = left ? -1 : 1.0;
	arcScale.y = top ? -1 : 1.0;
	//TODO: For some reason scaling does not work.
	//arcScale.x *= 0.5;
	//arcScale.y *= 0.5;

	if(redraw) {
		D3DLOCKED_RECT lockedRect;
		arcTexture->LockRect(0, &lockedRect, NULL, 0);
		byte *pixelBuffer = (byte*)(lockedRect.pBits);

		//Utils::Log(LOGFILE, Utils::ToString<int>(lockedRect.Pitch).c_str());

		for (int x = 0; x < arcDesc.Width; ++x) {
			for (int y = 0; y < arcDesc.Height; ++y) {
				//int currentPixel = (arcDesc.Width * y + x) * 4;
				DWORD currentPixel=(x*4+(y*(lockedRect.Pitch)));
				float maskHeight = angleRatio * (float)x;

				if((!top && maskHeight < y && angle < 90.0 || (!top && angle == 0)) || 
					(top && maskHeight > y || (top && angle == 90.0)) ) {
						pixelBuffer[currentPixel] = b;
						pixelBuffer[currentPixel+1] = g;
						pixelBuffer[currentPixel+2] = r;
						//pixelBuffer[currentPixel+3] = 200;
				} else {
					pixelBuffer[currentPixel] = 50;
					pixelBuffer[currentPixel+1] = 50;
					pixelBuffer[currentPixel+2] = 50;
				}
			}
		}

		arcTexture->UnlockRect(0);
	}

	D3DXMATRIX arcMatrix;
	D3DXMatrixTransformation2D(&arcMatrix, NULL, 0.0, &arcScale, NULL, rotationAngle * PI / 180, &arcPos);
	
	arcSprite->Begin(D3DXSPRITE_ALPHABLEND);
	//pIDirect3DDevice9->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
	//pIDirect3DDevice9->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
	//pIDirect3DDevice9->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);
	arcSprite->SetTransform(&arcMatrix);
	arcSprite->Draw(arcTexture, NULL, NULL, NULL, D3DCOLOR_RGBA(255, 255, 255, ConfigFile::StatsOpacity));
	arcSprite->End();	
}

void XenStats::RenderOldStats()
{
	maxHp = xenMemory->ReadMaxHP();
	maxMp = xenMemory->ReadMaxMP();
	//maxXp = level[xenMemory->ReadLevel() + 1];

	//Stats Background
	D3DSURFACE_DESC statsBgDesc;
	statsBgTexture->GetLevelDesc(0, &statsBgDesc);

	float baseScaleX = 1.0;
	float baseScaleY = 1.25;

	D3DXVECTOR2 statsBgScale;
	statsBgScale.x = baseScaleX * scaleX;
	statsBgScale.y = baseScaleY * scaleY;

	D3DXVECTOR2 statsBgPos;
	statsBgPos.x = (screenWidth / 2) - ((statsBgDesc.Width * statsBgScale.x) / 2);
	statsBgPos.y = screenHeight - (statsBgDesc.Height * statsBgScale.y) - (10 * scaleY);

	D3DXMATRIX statsBgMatrix;
	D3DXMatrixTransformation2D(&statsBgMatrix, NULL, 0.0, &statsBgScale, NULL, 0, &statsBgPos);

	statsBgSprite->Begin(D3DXSPRITE_ALPHABLEND);
	statsBgSprite->SetTransform(&statsBgMatrix);
	statsBgSprite->Draw(statsBgTexture, NULL, NULL, NULL, 0xFFFFFFFF);
	statsBgSprite->End();

	//Stats HP Display
	float hpPercent = xenMemory->ReadHPPercent();

	D3DSURFACE_DESC statsHpDesc;
	statsHpTexture->GetLevelDesc(0, &statsHpDesc);

	float statsHPScaleX = -((baseScaleX * (statsBgDesc.Width - 8)) / 2.0) / statsHpDesc.Width;
	float statsHPScaleY = ((baseScaleY * (statsBgDesc.Height - 8)) / 2.0) / statsHpDesc.Height;

	D3DXVECTOR2 statsHpScale;
	statsHpScale.x = statsHPScaleX * hpPercent * scaleX; //-1.93
	statsHpScale.y = statsHPScaleY * scaleY;

	D3DXVECTOR2 statsHpPos;
	statsHpPos.x = statsBgPos.x + ((statsBgDesc.Width * scaleX) / 2);
	statsHpPos.y = statsBgPos.y + (4 * scaleY);

	D3DXMATRIX statsHpMatrix;
	D3DXMatrixTransformation2D(&statsHpMatrix, NULL, 0.0, &statsHpScale, NULL, 0, &statsHpPos);

	statsHpSprite->Begin(D3DXSPRITE_ALPHABLEND);
	statsHpSprite->SetTransform(&statsHpMatrix);
	statsHpSprite->Draw(statsHpTexture, NULL, NULL, NULL, 0xFFFFFFFF);
	statsHpSprite->End();

	string HpStr = "";
	if (maxHp >= 0) {
		int curHpStr = hpPercent * maxHp;
		HpStr += Utils::ToString<int>(curHpStr) + "/" + Utils::ToString<int>(maxHp);
	}

	//Display HP Percent (Stats GUI needs to be bigger though.)
	//HpStr += " (" + Utils::ToString<int>(hpPercent * 100) + "%)";
	//992 936 831 951
	RECT statsHpFontRect = { statsHpPos.x + (statsHpDesc.Width * statsHPScaleX * scaleX), statsHpPos.y, statsHpPos.x, statsHpPos.y + (statsHpDesc.Height * statsHpScale.y) };
	statsHpFont->DrawText(NULL, HpStr.c_str(), -1, &statsHpFontRect, DT_CENTER, D3DCOLOR_XRGB(255, 255, 255));


	//Stats MP Display
	float mpPercent = xenMemory->ReadMPPercent();

	D3DSURFACE_DESC statsMpDesc;
	statsMpTexture->GetLevelDesc(0, &statsMpDesc);

	float statsMPScaleX = ((baseScaleX * (statsBgDesc.Width - 8)) / 2.0) / statsMpDesc.Width;
	float statsMPScaleY = ((baseScaleY * (statsBgDesc.Height - 8)) / 2.0) / statsMpDesc.Height;

	D3DXVECTOR2 statsMpScale;
	statsMpScale.x = statsMPScaleX * mpPercent * scaleX; //0.965
	statsMpScale.y = statsMPScaleY * scaleY;

	D3DXVECTOR2 statsMpPos;
	statsMpPos.x = statsBgPos.x + ((statsBgDesc.Width * scaleX) / 2);
	statsMpPos.y = statsBgPos.y + (4 * scaleY);

	D3DXMATRIX statsMpMatrix;
	D3DXMatrixTransformation2D(&statsMpMatrix, NULL, 0.0, &statsMpScale, NULL, 0, &statsMpPos);

	statsMpSprite->Begin(D3DXSPRITE_ALPHABLEND);
	statsMpSprite->SetTransform(&statsMpMatrix);
	statsMpSprite->Draw(statsMpTexture, NULL, NULL, NULL, 0xFFFFFFFF);
	statsMpSprite->End();

	string MpStr = "";
	if (maxMp >= 0) {
		int curMpStr = mpPercent * maxMp;
		MpStr += Utils::ToString<int>(curMpStr) + "/" + Utils::ToString<int>(maxMp);
	}

	//Display MP Percent (Stats GUI needs to be bigger though.)
	//MpStr += " (" + Utils::ToString<int>(mpPercent * 100) + "%)";
	RECT statsMpFontRect = { statsMpPos.x, statsMpPos.y, statsMpPos.x + (statsMpDesc.Width * statsMPScaleX * scaleX), statsMpPos.y + (statsMpDesc.Height * statsMpScale.y) };
	statsMpFont->DrawText(NULL, MpStr.c_str(), -1, &statsMpFontRect, DT_CENTER, D3DCOLOR_XRGB(255, 255, 255));


	//Stats XP Display
	float xpPercent = xenMemory->ReadXPPercent();

	D3DSURFACE_DESC statsXpDesc;
	statsXpTexture->GetLevelDesc(0, &statsXpDesc);

	RECT statsXpSrcRect;
	statsXpSrcRect.left = 32;
	statsXpSrcRect.right = 64;
	statsXpSrcRect.top = 64;
	statsXpSrcRect.bottom = 128;

	float statsXPScaleX = -((baseScaleY * (statsBgDesc.Height - 8)) / 2.0) / (statsXpSrcRect.right - statsXpSrcRect.left);
	float statsXPScaleY = (baseScaleX * (statsBgDesc.Width - 8)) / (statsXpSrcRect.bottom - statsXpSrcRect.top);

	D3DXVECTOR2 statsXpScale;
	statsXpScale.x = statsXPScaleX * scaleY; // -0.45 //Y because its rotated later
	statsXpScale.y = statsXPScaleY * xpPercent * scaleX; //3.88 //X because its rotated later

	D3DXVECTOR2 statsXpPos;
	statsXpPos.x = statsBgPos.x + (4 * scaleX);
	statsXpPos.y = statsHpPos.y + (statsHpDesc.Height * statsHpScale.y) + 1;

	D3DXMATRIX statsXpMatrix;
	D3DXMatrixTransformation2D(&statsXpMatrix, NULL, 0.0, &statsXpScale, NULL, -1.57079633, &statsXpPos);

	statsXpSprite->Begin(D3DXSPRITE_ALPHABLEND);
	statsXpSprite->SetTransform(&statsXpMatrix);
	statsXpSprite->Draw(statsXpTexture, &statsXpSrcRect, NULL, NULL, 0xFFFFFFFF);
	statsXpSprite->End();

	//Possible display xp numbers someday...
	string XpStr = "";

	//Display XP Percent
	XpStr += Utils::ToString<int>(xpPercent * 100) + "%";
	RECT statsXpFontRect = { statsBgPos.x, statsHpPos.y + (statsHpDesc.Height * statsHpScale.y), statsBgPos.x + (statsBgDesc.Width * scaleX), statsBgPos.y + (statsBgDesc.Height * statsBgScale.y) };
	statsXpFont->DrawText(NULL, XpStr.c_str(), -1, &statsXpFontRect, DT_CENTER, D3DCOLOR_XRGB(255, 255, 255));
}

void XenStats::ProcessInput()
{
	static bool keyReleased = true;

	if (Input::KeysDown(ConfigFile::StatsDisplayInput)) {
		if(keyReleased) {
			if (displayStats == 2) {
				displayStats = 0;
			} else { 
				++displayStats;	
			}
		}
		keyReleased = false;
	} else {
		keyReleased = true;
	}
}
void XenStats::Release()
{
	hpTopArcTexture->Release();
	hpBottomArcTexture->Release();
	mpTopArcTexture->Release();
	mpBottomArcTexture->Release();
	xpTopArcTexture->Release();
	xpBottomArcTexture->Release();
	arcSprite->Release();
	statsBgTexture->Release();
	statsBgSprite->Release();
	statsHpTexture->Release();
	statsHpSprite->Release();
	statsHpFont->Release();
	statsMpTexture->Release();
	statsMpSprite->Release();
	statsMpFont->Release();
	statsXpTexture->Release();
	statsXpSprite->Release();
	statsXpFont->Release();

	delete(xenMemory);
}